<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <title>A股当前与前高前低占比计算</title>
    <script src="https://cdn.bootcdn.net/ajax/libs/vue/3.4.37/vue.global.js"></script>
    <script src="https://cdn.tailwindcss.com"></script>
    <script src="https://cdn.bootcdn.net/ajax/libs/naive-ui/2.39.0/index.js"></script>
    <!-- <script src="https://cdn.bootcdn.net/ajax/libs/vue-demi/0.14.10/index.iife.min.js"></script>
    <script src="https://cdn.bootcdn.net/ajax/libs/pinia/2.2.1/pinia.esm-browser.min.js"></script>
    <script src="https://cdn.bootcdn.net/ajax/libs/pinia/2.2.1/pinia.iife.prod.min.js"></script> -->
    <script src="https://unpkg.com/vue-demi"></script>
    <script src="https://unpkg.com/pinia"></script>
    <style>
      #app {
        height: 100vh;
      }
    </style>
  </head>
  <body>
    <div id="app" class="bg-green-50">
      <n-grid x-gap="12" :cols="3">
        <n-gi>
          <n-card title="计算前高前低占比">
            <n-form
              ref="formRef"
              :label-width="120"
              label-placement="left"
              :model="formValue"
              :size="'small'"
            >
              <n-form-item label="前高" path="height">
                <n-input-number
                  v-model:value="formValue.height"
                  :step="10"
                  :min="0"
                  class="w-full"
                />
              </n-form-item>
              <n-form-item label="前低" path="low">
                <n-input-number
                  v-model:value="formValue.low"
                  :step="10"
                  :min="0"
                  class="w-full"
                />
              </n-form-item>
              <n-form-item label="当前" path="current">
                <n-input-number
                  v-model:value="formValue.current"
                  :step="10"
                  :min="0"
                  class="w-full"
                />
              </n-form-item>
              <n-form-item label="距离前高"> {{thanHeight}} </n-form-item>
              <n-form-item label="距离前低"> {{thanLow}} <b class="ml-2 text-red-500">高/低比例：{{ (thanHeight / thanLow).toFixed(2)  }}</b></n-form-item>
              <div
                class="text-4xl text-center text-red-500 mt-8"
                v-if="thanLow < 100"
              >
                开始着手建仓
              </div>
            </n-form>
          </n-card>
        </n-gi>
        <n-gi>
          <need-money></need-money>
        </n-gi>
        <n-gi>
          <npv-app></npv-app>
        </n-gi>
      </n-grid>
    </div>

    <!-- 以年消耗与寿命推算需要的总资金量 家庭根据开支需要的总资金 -->
    <template id="need-money">
      <n-card title="家庭根据开支需要的总资金" >
        <n-form
          ref="needMoneyFormRef"
          :label-width="120"
          label-placement="left"
          :model="needMoneyForm"
          :size="'small'"
        >
          <n-form-item label="单人开销" path="useByMonth">
            <n-input-number
              v-model:value="needMoneyForm.useByMonth"
              :step="10"
              :min="0"
              class="w-full"
            >
              <template #suffix>
                元/人/月
              </template>
            </n-input-number>
          </n-form-item>
          <n-form-item label="家庭总人数" path="usePerson">
            <n-input-number
              v-model:value="needMoneyForm.usePerson"
              :step="1"
              :min="0"
              class="w-full"
            >
            <template #suffix>
              人
            </template>
          </n-input-number>
          </n-form-item>
          <n-form-item label="平均寿命" path="averageLifespan">
            <n-input-number
              v-model:value="needMoneyForm.averageLifespan"
              :step="1"
              :min="0"
              class="w-full"
            ><template #suffix>
              年
            </template>
          </n-input-number>
          </n-form-item>
          <n-form-item label="当前年龄" path="currentLifespan">
            <n-input-number
              v-model:value="needMoneyForm.currentLifespan"
              :step="1"
              :min="0"
              class="w-full"
            >
            <template #suffix>
              岁
            </template>
          </n-input-number>
          </n-form-item>
          <n-form-item label="需要的总资金"> <span class="text-red-500">{{needMoneyTotal}}</span> 元 
            <span class="ml-2">距离理论死亡 <b class="text-red-500">{{ needMoneyForm.averageLifespan - needMoneyForm.currentLifespan }}</b> 年</span>
            <span class="ml-2">距离退休<b class="text-red-500">{{ 65 - needMoneyForm.currentLifespan }}</b>年(65岁退)</span>
          </n-form-item>
        </n-form>
      </n-card>
    </template>

    <!-- NPV 净现值计算 -->
    <template id="npv-app">
      <n-card title="NPV 净现值计算" >
        <n-form
          ref="npvFormRef"
          :label-width="150"
          label-placement="left"
          :model="npvForm"
          :size="'small'"
        >
          <n-form-item label="初始投资值" path="current">
            <n-input-number
              v-model:value="npvForm.current"
              :step="10"
              :min="0"
              class="w-full"
            ><template #suffix>
              元
            </template>
          </n-input-number>
          </n-form-item>
          <n-form-item label="年化利率" path="r">
            <n-input-number
              :value="npvForm.r * 100"
              :step="1"
              :min="0"
              :max="100"
              class="w-full"
              @update:value="npvForm.r = $event / 100"
            ><template #suffix>
              %
            </template>
          </n-input-number>
          </n-form-item>
          <n-form-item label="投资周期" path="n">
            <n-input-number
              v-model:value="npvForm.n"
              :step="1"
              :min="0"
              class="w-full"
            >
            <template #suffix>
              年
            </template>
          </n-input-number>
          </n-form-item>
          <n-form-item label="每年末额外追加投资" path="money">
            <n-input-number
              v-model:value="npvForm.money"
              :step="10"
              :min="0"
              class="w-full"
            >
            <template #suffix>
              元
            </template>
          </n-input-number>
          </n-form-item>
          <n-form-item label="净现值"> <b class="text-red-500">{{npv}}</b> 元 
            <span class="ml-2">当时岁数 <b class="text-red-500">{{ needMoneyForm.currentLifespan + npvForm.n }}</b> 岁</span>
          </n-form-item>
        </n-form>
    </template>

    <script>
      // 获取script标签内容
      function getScriptContent (script) {
        return new Promise((resolve, reject) => {
          var xhr = new XMLHttpRequest();
          xhr.open("GET",script.src)
          xhr.onreadystatechange = function () {
            if(xhr.readyState === XMLHttpRequest.DONE && xhr.status === 200) {
              resolve(xhr.responseText);
            }
          };
          xhr.send();
        })
      };
      // 创建script标签
      function createJsonp(url, callback) {
        var script = document.createElement('script');
        script.setAttribute("type","text/javascript");
        script.src = url;
        document.body.appendChild(script);
        script.onload = function () {
          callback(script);
        }
      }

      const { ref, computed, defineComponent } = Vue;
      const { defineStore, createPinia, storeToRefs } = Pinia;

      // 全局状态
      const useMainStore = defineStore("main", () => {
        const formValue = ref({
          height: 3174,
          low: 2635,
          current: 2865,
        });

        const needMoneyForm = ref({
          useByMonth: 1000, // 单人开销
          usePerson: 3, // 家庭总人数
          averageLifespan: 78, // 年寿命 默认为女性 平均寿命
          currentLifespan: 32, // 当前寿命
        });

        const npvForm = ref({
          current: 80000, // 初始投资值
          r: 0.05, // 年化利率
          n: 10, // 投资周期
          money: 100000 // 年末额外追加投资
        });

        // 初始化异步获取
        createJsonp('http://qt.gtimg.cn/q=s_sh000001', async (script) => {
          const content = await getScriptContent(script);
          const d = content.match(/"([^"]*)"/)
          if (d.length > 1) {
            const sh = d[1];
            const [_, name, code, current, point, per, vol, amount ] = sh.split('~').filter(Boolean)
            formValue.value.current = parseInt(current)
            console.log(`股票名称：${name} 股票代码：${code} 当前价：${current} 点差：${point} 涨跌幅：${per} 成交量：${vol} 成交额：${amount}, 原数据：${sh}`);
          }
          document.body.removeChild(script);
        });

        return {
          formValue,
          needMoneyForm,
          npvForm
        }
      })

      // 子应用 以年消耗与寿命推算需要的总资金量
      const NeedMoney = defineComponent({
        name: "NeedMoney",
        setup() {
          const { needMoneyForm } = storeToRefs(useMainStore())

          const needMoneyTotal = /** 计算需要的总资金 */ computed(() => {
            const { useByMonth, usePerson, averageLifespan, currentLifespan } =
              needMoneyForm.value;
            return (
              useByMonth * 12 * usePerson * (averageLifespan - currentLifespan)
            );
          });
          return {
            needMoneyForm,
            needMoneyTotal,
          };
        },
        template: "#need-money",
      });
      
      // NPV 净现值计算
      const NpvApp = defineComponent({
        name: "NpvApp",
        setup() {
          const { npvForm, needMoneyForm } = storeToRefs(useMainStore())

          const calc = (year, current, r, n) => {
            if (year <= 0){
              return current
            } else {
              const a = current * (1 + r) + n
              return calc(year - 1, a, r, n)
            }
          }

          const npv = /** 计算净现值 */ computed(() => {
            const { current, r, n, money } = npvForm.value;
            return calc(n, current, r, money).toFixed();
          });
          return {
            needMoneyForm,
            npvForm,
            npv,
          }
        },
        template: "#npv-app",
      })

      // 主应用
      const appVue = {
        setup() {
          const { formValue } = storeToRefs(useMainStore());

          const thanHeight = /** 距离前高 */ Vue.computed(
            () => formValue.value.height - formValue.value.current
          );
          const thanLow = /** 距离前低 */ Vue.computed(
            () => formValue.value.current - formValue.value.low
          );

          return {
            thanHeight,
            thanLow,
            formValue,
          };
        },
      };
      
      const vm = Vue.createApp(appVue)
        .use(naive)
        .use(createPinia())
        .component("NeedMoney", NeedMoney)
        .component("NpvApp", NpvApp)
        .mount("#app");
    </script>
  </body>
</html>
